#include <stdlib.h>
#include <string.h>
#include <event2/bufferevent.h>
#include "zhttp.h"
#include "linklist.h"
#include "utils.h"
#include "libevent_http.h"

struct zhttp* zhttp_new(struct event_base* base)
{
    if(!base){return NULL;}

    struct zhttp* zhp = NULL;
    struct Request* request = NULL;
    
    //初始化zhp
    zhp = (struct zhttp*)malloc(sizeof(struct zhttp));
    if(NULL ==  zhp){
        printf("malloc zhttp failed, %s, %d\n", __FUNCTION__, __LINE__);
        return NULL;
    }

    //初始化 zhp->status
    zhp->status = ZHTTP_FLAG_LINE;

    //初始化 zhp->request
    request = request_new();
    if(NULL == request){
        printf("malloc request failed, %s, %d\n", __FUNCTION__, __LINE__);
        goto error;
    }
    zhp->request = request;
    
    //初始化   zhp->buf
    zhp->buf = NULL;

    //初始化 zhp->base
    zhp->base = base;

    return (zhp);

error:
    if(zhp){
        free(zhp);
        return NULL;
    }
}

void  zhttp_clear(struct zhttp* http)
{
    struct event_base* base = http->base;
    zhttp_free(http);
    http = zhttp_new(base);
}

void zhttp_free(struct zhttp* http)
{
    if(http->buf){
        free(http->buf);
    }
    if(http->request){
        request_free(http->request);
    }
    if(http){
        free(http);
    }
}

struct Request* request_new()
{
    struct Request* request = NULL;
    struct RequestLine* line = NULL;
    LinkList* header = NULL;

    //初始化request
    request = malloc(sizeof(struct Request));
    if(NULL ==  request){
        printf("malloc Request failed, %s, %d\n", __FUNCTION__, __LINE__);
        return NULL;
    }
    
    //初始化line
    line = malloc(sizeof(struct RequestLine));
    if(NULL ==  line){
        printf("malloc RequestLine failed, %s, %d\n", __FUNCTION__, __LINE__);
        goto error;
    }
    memset(line, 0, sizeof(struct RequestLine));
    line->url = NULL;
    request->line = line;

    //初始化header
    header = LinkList_Create();
    if(NULL == header){
        goto error;
    }
    request->header = header;

    //初始化body
    request->body = NULL;

    return request;
error:
    if(request){
        free(request);
    }
    if(line){
        free(line);
    }
    return NULL;
}

void  request_free(struct Request* request)
{
    if(request){
        if(request->line){
            if(request->line->url){
                free(request->line->url);
            }
            free(request->line);
        }
        if(request->header){
            while (LinkList_Length(request->header) > 0){
                struct rhkeyval* keyval = (struct rhkeyval*)LinkList_Delete(request->header, 0);
                if(keyval->key){
                    free(keyval->key);
                }
                if(keyval->value){
                    free(keyval->value);
                }
                free(keyval);
            }
            LinkList_Destory(request->header);
        }
        if(request->body){
            free(request->body);
        }
        free(request);
    }
}

void append_http_buf(struct zhttp* http, char* buf, int len)
{
    char* str = buftostr(buf, len);
    char* old_http_buf = http->buf;

    int old_len = 0;
    int malloc_len = 0;
    if(old_http_buf != NULL){
        old_len = strlen(old_http_buf);
    }

    malloc_len = ( (old_len+len+1) / 1024 + 1)*1024;
    http->buf = malloc_nchar_by_len(malloc_len);
    if(old_http_buf != NULL){
        strncpy(http->buf, old_http_buf, strlen(old_http_buf));
    }
    strncpy(http->buf+strlen(http->buf), str, strlen(str));

    free_nchar(str);
    free_nchar(old_http_buf);
    //printf("all :%s\n", http->buf);
}

void http_line_parse(struct zhttp* http, struct bufferevent *bev)
{
    char* p = NULL;
    int ret = 0;
    if((sizeof(http->buf) - 1)  > ZHTTP_MAX_LINE_SIZE){//url超过这个
        send_response_head(bev, 414,"url size long", get_file_type(".html"), -1);
        bufferevent_free(bev);
        zhttp_clear(http);
        return;
    }
    if( (p = strstr(http->buf, "\r\n")) == NULL){
        return;
    }
    p += 2 ;
    ret = request_set_line(http, p);
    if(ret < 0){
        send_response_head(bev, 415,"invalid request line", get_file_type(".html"), -1);
        bufferevent_free(bev);
        zhttp_clear(http);
    }
    http->status = ZHTTP_FLAG_HEAD;
}
void http_header_parse(struct zhttp* http, struct bufferevent *bev)
{
    if( (sizeof(http->buf) - 1)  > ZHTTP_MAX_HEADER_SIZE){
        send_response_head(bev, 414,"head size long", get_file_type(".html"), -1);
        bufferevent_free(bev);
        zhttp_clear(http);
        return ;
    }
    char* p = NULL;
    if((p = strstr(http->buf, "\r\n\r\n")) == NULL){
        return;
    }
    p += 4;
    request_set_head(http, p);
    http->status = ZHTTP_FLAG_BODY;
}

void http_body_parse(struct zhttp* http, struct bufferevent *bev)
{
   int s =  LinkList_Length(http->request->header) ;
   printf("head length:%d \n", s);
    //先打印以下head;
    while ( LinkList_Length(http->request->header) > 0){
        struct rhkeyval* kev =  (struct rhkeyval* )LinkList_Get(http->request->header, 0);
        printf("before head key[%s] value[%s]\n", kev->key, kev->value);
    }
    
}

int request_set_line(struct zhttp* http, char* p)
{
    int len = strlen(http->buf)- strlen(p);
    char* str = buftostr(http->buf, len);
    
    printf("current request line:%s", str);

    if ((http->request->line->url =  malloc(len)) == NULL){
        printf("malloc http->request->line->url faled:%s %d\n", __FUNCTION__, __LINE__);
        return -1;
    }

    sscanf(str, "%[^ ] %[^ ] %[^ ]\r\n", 
                    http->request->line->method, 
                    http->request->line->url, 
                    http->request->line->protocol);

    printf("method[%s], url[%s], version[%s]\n", 
                    http->request->line->method, 
                    http->request->line->url, 
                    http->request->line->protocol);

    if(http_allowed_method(http->request->line->method)  < 0){
        printf("http method not allowed : %s %d\n", __FUNCTION__, __LINE__);
        free_nchar(str);
        return -1;
    }
    
    char* old_http_buf = http->buf;
    http->buf = malloc(strlen(p)+1);
    memset(http->buf,0,sizeof(http->buf));
    strncpy(http->buf, old_http_buf+len, strlen(p));

    free_nchar(old_http_buf);
    free_nchar(str);

    return 0;
}

int request_set_head(struct zhttp* http, char* p)
{
    int len = strlen(http->buf)- strlen(p);
    char* str = buftostr(http->buf, len);
    char* h = NULL;
    char* b = NULL;
    printf("current request heads: %s", str);

    h = str;
    b = str;
    char* head = NULL;
    int headlen;
    char key[1024] ={0};
    char value[1024] ={0};
    while (  (h = strstr(h, "\r\n")) != NULL){
        h += 2;
        headlen = strlen(b) - strlen(h);
        if(headlen == 2){
            break;
        }
        head = buftostr(b, headlen);
        sscanf(head, "%[^:]: %[^\r]\n", key, value);
        printf("every head: %s, key[%ld]:%s, value[%ld]:%s\n", head, strlen(key), key, strlen(value),value);       
        
        //添加到 
        struct rhkeyval* kev = malloc(sizeof(struct rhkeyval));
        kev->key =  buftostr(key, strlen(key));
        strncpy(kev->key, key, strlen(key));
        kev->value = buftostr(value, strlen(value));
        strncpy(kev->value, value, strlen(value));
        LinkList_Insert(http->request->header, (LinkListNode*)kev, 0);

        b = h;
        free_nchar(head);
    }
    
    char* old_http_buf = http->buf;
    http->buf = malloc(strlen(p)+1);
    memset(http->buf, 0, strlen(p)+1);
    strncpy(http->buf, old_http_buf+len, strlen(p));

    free_nchar(old_http_buf);
    free_nchar(str);
    return 0;
}

int http_allowed_method(char* method)
{
    if(strlen(method) == 3 &&  strncasecmp("get",method, 3) == 0){
        return 0;
    }
    if(strlen(method) == 4 &&  strncasecmp("post",method, 4) == 0){
        return 0;
    }
    return -1;
}